#ifndef AUTOMATIC_BOX_CREATOR_REGISTRATOR_H_JM_20120702
#define AUTOMATIC_BOX_CREATOR_REGISTRATOR_H_JM_20120702
/**
 * @file AutomaticBoxCreatorRegistration.h
 * Nastroje pre automaticku registraciu tvorcov boxov do factory na boxy 
 * v runtime. Obsahuje makra pre registraciu v jednoduchych pripadoch vytvarania 
 * boxov a tiez triedu AutomaticBoxCreatorRegistration, ktora umoznuje 
 * registrovat uzivatelsky definovany kreator (po splneni niekolkych podmienok).
 * 
 **/

// ## C++
#include <string>
// ##
#include "BoxCreatorRegistrator.h"
#include "PlainBoxModelCreator.h"

/**
 * Registracia automatickeho vytvaraca boxu do runtime. Argument je boxu ktoreho 
 * vygenerovany tvorca ma byt zaregistrovany(pridany) do factory, ktora vyraba 
 * boxy pre runtime.
 * 
 * Pouzitie makra sa predpoklada raz v samostatnej kompilacnej jednotke  
 * (cpp subor) tak, aby nebolo viditelne v inych castiach programu. 
 * Pokial splnenie tejto podmienky nie je mozne, tak je mozne pouzit makro  
 * {@link REGISTER_BOX_TO_RUNTIME_SPECIFIC(BoxModel,BoxId,Postfix)}, ktore 
 * umoznuje doplnit postfix generovaneho registratora tak aby nedochadzalo 
 * ku konfliktu nazvov.  
 **/
//#define REGISTER_BOX_TO_RUNTIME(boxName, Box) \
//	REGISTER_BOX_TO_RUNTIME_SPECIFIC(boxName, Box, DefaultName);

/**
 * Makro poskytujuce rovnaku funkcionalitu ako makro 
 * {@link REGISTER_BOX_TO_RUNTIME(BoxModel,BoxId)}. Makro obsahuje naviac  
 * argument, pomocou ktoreho je mozne doplnit nazov generovaneho registratora. 
 * Tato schopnost je potrebna pokial je viacero registracii v ramcii jednej 
 * kompilacnej jednotky a kazdy registrator teda potrebuje unikatny nazov.
 * 
 * V standardnom pripade tj. jeden box ~ jeden subor (h aj cpp). Staci zadat 
 * makro {@link REGISTER_BOX_TO_RUNTIME(BoxModel,BoxId)} do cpp a potom nie je 
 * potrebne rozlisovat registratory.
 **/
//#define REGISTER_BOX_TO_RUNTIME_SPECIFIC(boxName, Box, Postfix) \
//	jm4bbx::AutomaticBoxCreatorRegistration<\
//		jm4bbx::PlainBoxModelCreator<Box> > \
//			registerBoxCreator__##Postfix(boxName);

#define REGISTER_BOX_TO_RUNTIME_BASE(boxName, box) \
	REGISTER_BOX_TO_RUNTIME_PARAMS(boxName, box, 0)

#define REGISTER_BOX_TO_RUNTIME_PARAMS(boxName, box, Params) \
	jm4bbx::AutomaticBoxCreatorRegistration<\
	jm4bbx::PlainBoxModelCreator<box> > \
	registerBoxCreator__##boxName(#boxName, Params);


namespace jm4bbx {
	/**
	 * Sablona pre automaticky registrator tvorcu boxu do runtimu. 
	 * Registrovanie tvrocov boxov je decentralizovane a kazdy box si zodpoveda 
	 * za registraciu svojho tvorcu do runtime. Registracia je docielena 
	 * instanciaciou triedy vygenerovanej z tejto sablony pre konkretneho tvorcu
	 * boxu. 
	 * 
	 * @code 
	 * // Zaregistrovanie tvrocu boxov typu BoxCreatorImpl do factory pre boxy
	 * // v runtime.
	 * AutomaticBoxCreatorRegistration<BoxCreatorImpl> creatror;
	 * @endcode
	 * 
	 * V pripade tvorcu, ktory vytvara box priamo pomocou konstruktoru a 
	 * neupravuje parametre (len ich preda konstruktoru) je vhodne pouzit 
	 * registracne makro {@link REGISTER_BOX_TO_RUNTIME} alebo pripadne
	 * {@link REGISTER_BOX_TO_RUNTIME_SPECIFIC}. V tomto pripade je pouzity 
	 * predpripraveny tvorca boxov.
	 * 
	 * Alternativne je mozne tvorcu boxu registrovat aj priamo.
	 * @code
	 * // id - unikatny identifikator boxu v ramci runtime pouzivany v modele
	 * // vypoctu pre identifikaciu boxu.
	 * // creator - instancia tvorcu, ktora je schopna vytvorit model boxu na 
	 * // zaklade ktoreho je mozne zostrojit samotny box v runtime.
	 * BoxCreatorRegistrator::getInstance()->registerCreator(id, creator);
	 * @endcode
	 * 
	 * @tparam BoxModelCreatorType Tvorca modelov boxov - trieda dodrzujuca 
	 * rozhranie {@link jm4bbx::BoxModelCreator} a naviac definujuca typ 
	 * ModelType, ktory zodpoveda typu vytvaraneho modelu. 
	 * 
	 **/
	template<class BoxModelCreatorType>
	class AutomaticBoxCreatorRegistration {
	public:
		/**
		 * Konstruktor, ktory zaregistruje tvorcu boxov do factory pre runtime.
		 * Typ tvorcu je predany ako parameter sablony triedy. 
		 **/
		AutomaticBoxCreatorRegistration(const std::string& boxName, void*) {
			BoxCreatorRegistrator::getInstance()->registerCreator(
				boxName,
				//BoxModelCreatorType::BoxType::BoxIO::BOX_ID, 
				new BoxModelCreatorType());		
		}
	};
}
#endif
